﻿// Decompiled with JetBrains decompiler
// Type: Netick.NetickAllocator
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#nullable disable
namespace Netick;

public sealed class NetickAllocator : ISafeAllocator
{
  internal const int ALIGN_SIZE_LOG2 = 3;
  internal const int ALIGN_SIZE = 8;
  internal const int FL_INDEX_MAX = 32 /*0x20*/;
  internal const int SL_INDEX_COUNT = 32 /*0x20*/;
  internal const int FL_INDEX_SHIFT = 8;
  internal const int FL_INDEX_COUNT = 25;
  internal const int SMALL_BLOCK_SIZE = 256 /*0x0100*/;
  internal const int SL_INDEX_COUNT_LOG2 = 5;
  internal const ulong block_header_free_bit = 1;
  internal const ulong block_header_prev_free_bit = 2;
  internal static ulong block_header_overhead = (ulong) sizeof (int*);
  private ulong block_size_min = (ulong) (sizeof (NetickAllocator.block_header_t) - sizeof (NetickAllocator.block_header_t*));
  private ulong block_size_max = 4294967296 /*0x0100000000*/;
  internal NetickAllocator.control_t _control;
  public List<NetickAllocator.MemoryPool> Blocks = new List<NetickAllocator.MemoryPool>(32 /*0x20*/);
  internal readonly long _poolSize;

  private static ulong block_start_offset
  {
    get => (ulong) (sizeof (NetickAllocator.block_header_t*) + sizeof (int*));
  }

  internal unsafe NetickAllocator(long poolSizeBytes)
  {
    this._poolSize = poolSizeBytes;
    this._control = new NetickAllocator.control_t();
    this.control_construct(this._control);
    this.AddPool(this.CreatePool(this._poolSize), (ulong) poolSizeBytes);
  }

  unsafe ~NetickAllocator()
  {
    for (int index = 0; index < this.Blocks.Count; ++index)
      MemoryAllocation.Free(this.Blocks[index].Ptr);
    this.Blocks.Clear();
  }

  private unsafe void* CreatePool(long byteSize)
  {
    void* ptr = MemoryAllocation.Malloc(byteSize);
    MemoryAllocation.Clear(ptr, byteSize);
    this.Blocks.Add(new NetickAllocator.MemoryPool()
    {
      ByteSize = byteSize,
      Ptr = ptr
    });
    return ptr;
  }

  public unsafe void AddNewPool(bool isMain)
  {
    void* pool = this.CreatePool(this._poolSize);
    if (!isMain)
      return;
    this.AddPool(pool, (ulong) this._poolSize);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public unsafe void CopyTo(NetickAllocator dest)
  {
    NetickAllocator.Assert(dest.Blocks.Count == this.Blocks.Count);
    NetickAllocator.Assert(dest._poolSize == this._poolSize);
    for (int index = 0; index < this.Blocks.Count; ++index)
      MemoryAllocation.Copy(dest.Blocks[index].Ptr, this.Blocks[index].Ptr, this._poolSize);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  internal static void Assert(bool d, string msg = "") => NetickLogger.Assert(d, (object) msg);

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private int tlsf_fls_generic(uint word)
  {
    int num = 32 /*0x20*/;
    if (word == 0U)
      --num;
    if (((int) word & -65536) == 0)
    {
      word <<= 16 /*0x10*/;
      num -= 16 /*0x10*/;
    }
    if (((int) word & -16777216 /*0xFF000000*/) == 0)
    {
      word <<= 8;
      num -= 8;
    }
    if (((int) word & -268435456 /*0xF0000000*/) == 0)
    {
      word <<= 4;
      num -= 4;
    }
    if (((int) word & -1073741824 /*0xC0000000*/) == 0)
    {
      word <<= 2;
      num -= 2;
    }
    if (((int) word & int.MinValue) == 0)
    {
      word <<= 1;
      --num;
    }
    return num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private int tlsf_fls_sizet(ulong size)
  {
    int word = (int) (size >> 32 /*0x20*/);
    return word == 0 ? this.tlsf_fls((uint) ((ulong) (int) size & (ulong) uint.MaxValue)) : 32 /*0x20*/ + this.tlsf_fls((uint) word);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private int tlsf_ffs(uint word) => this.tlsf_fls_generic(word & (uint) (~(int) word + 1)) - 1;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private int tlsf_fls(uint word) => this.tlsf_fls_generic(word) - 1;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_from_ptr(void* ptr)
  {
    return (NetickAllocator.block_header_t*) ((IntPtr) ptr - (IntPtr) NetickAllocator.block_start_offset);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  internal static unsafe void* block_to_ptr(NetickAllocator.block_header_t* block)
  {
    return (void*) ((IntPtr) block + (IntPtr) NetickAllocator.block_start_offset);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  internal static unsafe NetickAllocator.block_header_t* offset_to_block(void* ptr, ulong size)
  {
    return (NetickAllocator.block_header_t*) ((IntPtr) ptr + (IntPtr) size);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong align_up(ulong x, ulong align)
  {
    NetickAllocator.Assert(((long) align & (long) align - 1L) == 0L, "Netick Allocator: must align to a power of two");
    return (ulong) ((long) x + ((long) align - 1L) & ~((long) align - 1L));
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong align_down(ulong x, ulong align)
  {
    NetickAllocator.Assert(((long) align & (long) align - 1L) == 0L, "Netick Allocator: must align to a power of two");
    return x - (x & align - 1UL);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void* align_ptr(void* ptr, ulong align)
  {
    void* voidPtr = (void*) ((IntPtr) ptr + (IntPtr) (ulong) ((long) align - 1L & ~((long) align - 1L)));
    NetickAllocator.Assert(((long) align & (long) align - 1L) == 0L, "Netick Allocator: must align to a power of two");
    return voidPtr;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong tlsf_min(ulong a, ulong b) => a >= b ? b : a;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong tlsf_max(ulong a, ulong b) => a <= b ? b : a;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong adjust_request_size(ulong size, ulong align)
  {
    ulong num = 0;
    if (size != 0UL)
    {
      ulong a = this.align_up(size, align);
      if (a < this.block_size_max)
        num = this.tlsf_max(a, this.block_size_min);
    }
    return num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void mapping_insert(ulong size, int* fli, int* sli)
  {
    int num1;
    int num2;
    if (size < 256UL /*0x0100*/)
    {
      num1 = 0;
      num2 = (int) size / 8;
    }
    else
    {
      int num3 = this.tlsf_fls_sizet(size);
      num2 = (int) (size >> num3 - 5) ^ 32 /*0x20*/;
      num1 = num3 - 7;
    }
    *fli = num1;
    *sli = num2;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void mapping_search(ulong size, int* fli, int* sli)
  {
    if (size >= 256UL /*0x0100*/)
    {
      ulong num = (ulong) (1L << this.tlsf_fls_sizet(size) - 5) - 1UL;
      size += num;
    }
    this.mapping_insert(size, fli, sli);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* search_suitable_block(
    NetickAllocator.control_t control,
    int* fli,
    int* sli)
  {
    int x = *fli;
    int num = *sli;
    uint word1 = control.sl_bitmap[x] & (uint) (-1 << num);
    if (word1 == 0U)
    {
      uint word2 = control.fl_bitmap & (uint) (-1 << x + 1);
      if (word2 == 0U)
        return (NetickAllocator.block_header_t*) null;
      x = this.tlsf_ffs(word2);
      *fli = x;
      word1 = control.sl_bitmap[x];
    }
    NetickAllocator.Assert(word1 > 0U, "Netick Allocator: internal error - second level bitmap is null");
    int y = this.tlsf_ffs(word1);
    *sli = y;
    return control.GetBlock(x, y);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void remove_free_block(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    int fl,
    int sl)
  {
    NetickAllocator.block_header_t* prevFree = block->prev_free;
    NetickAllocator.block_header_t* nextFree = block->next_free;
    NetickAllocator.Assert((IntPtr) prevFree != IntPtr.Zero, "Netick Allocator: prev_free field can not be null");
    NetickAllocator.Assert((IntPtr) nextFree != IntPtr.Zero, "Netick Allocator: next_free field can not be null");
    nextFree->prev_free = prevFree;
    prevFree->next_free = nextFree;
    if (control.GetBlock(fl, sl) != block)
      return;
    control.SetBlock(fl, sl, nextFree);
    if (nextFree != control.block_null)
      return;
    control.sl_bitmap[fl] &= (uint) ~(1 << sl);
    if (control.sl_bitmap[fl] != 0U)
      return;
    control.fl_bitmap &= (uint) ~(1 << fl);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void insert_free_block(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    int fl,
    int sl)
  {
    NetickAllocator.block_header_t* block1 = control.GetBlock(fl, sl);
    NetickAllocator.Assert((IntPtr) block1 != IntPtr.Zero, "Netick Allocator: free list cannot have a null entry");
    NetickAllocator.Assert((IntPtr) block != IntPtr.Zero, "Netick Allocator: cannot insert a null entry into the free list");
    block->next_free = block1;
    block->prev_free = control.block_null;
    block1->prev_free = block;
    NetickAllocator.Assert(NetickAllocator.block_to_ptr(block) == this.align_ptr(NetickAllocator.block_to_ptr(block), 8UL), "Netick Allocator: block not aligned properly");
    control.SetBlock(fl, sl, block);
    control.fl_bitmap |= (uint) (1 << fl);
    control.sl_bitmap[fl] |= (uint) (1 << sl);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void block_remove(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block)
  {
    int fl;
    int sl;
    this.mapping_insert(block->GetSize(), &fl, &sl);
    this.remove_free_block(control, block, fl, sl);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void InsertBlock(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block)
  {
    int fl;
    int sl;
    this.mapping_insert(block->GetSize(), &fl, &sl);
    this.insert_free_block(control, block, fl, sl);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe bool block_can_split(NetickAllocator.block_header_t* block, ulong size)
  {
    return block->GetSize() >= (ulong) sizeof (NetickAllocator.block_header_t) + size;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_split(
    NetickAllocator.block_header_t* block,
    ulong size)
  {
    NetickAllocator.block_header_t* block1 = NetickAllocator.offset_to_block(NetickAllocator.block_to_ptr(block), size - NetickAllocator.block_header_overhead);
    ulong size1 = block->GetSize() - (size + NetickAllocator.block_header_overhead);
    NetickAllocator.Assert(NetickAllocator.block_to_ptr(block1) == this.align_ptr(NetickAllocator.block_to_ptr(block1), 8UL), "Netick Allocator: remaining block not aligned properly");
    NetickAllocator.Assert((long) block->GetSize() == (long) size1 + (long) size + (long) NetickAllocator.block_header_overhead);
    block1->SetSize(size1);
    NetickAllocator.Assert(block1->GetSize() >= this.block_size_min, "Netick Allocator: block split with invalid size");
    block->SetSize(size);
    block1->block_mark_as_free(block1);
    return block1;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_absorb(
    NetickAllocator.block_header_t* prev,
    NetickAllocator.block_header_t* block)
  {
    NetickAllocator.Assert(!prev->IsLast(), "Netick Allocator: previous block can't be last");
    prev->size += block->GetSize() + NetickAllocator.block_header_overhead;
    prev->block_link_next(prev);
    return prev;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_merge_prev(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block)
  {
    if (block->IsPrevFree() != 0)
    {
      NetickAllocator.block_header_t* blockHeaderTPtr = block->block_prev(block);
      NetickAllocator.Assert((IntPtr) blockHeaderTPtr != IntPtr.Zero, "Netick Allocator: prev physical block can't be null");
      NetickAllocator.Assert(blockHeaderTPtr->IsFree() != 0, "Netick Allocator: prev block is not free though marked as such");
      this.block_remove(control, blockHeaderTPtr);
      block = this.block_absorb(blockHeaderTPtr, block);
    }
    return block;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_merge_next(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block)
  {
    NetickAllocator.block_header_t* block1 = block->block_next(block);
    NetickAllocator.Assert((IntPtr) block1 != IntPtr.Zero, "Netick Allocator: next physical block can't be null");
    if (block1->IsFree() != 0)
    {
      NetickAllocator.Assert(!block->IsLast(), "Netick Allocator: previous block can't be last");
      this.block_remove(control, block1);
      block = this.block_absorb(block, block1);
    }
    return block;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void block_trim_free(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    ulong size)
  {
    NetickAllocator.Assert(block->IsFree() != 0, "Netick Allocator: block must be free");
    if (!this.block_can_split(block, size))
      return;
    NetickAllocator.block_header_t* block1 = this.block_split(block, size);
    block->block_link_next(block);
    block1->SetPrevFree();
    this.InsertBlock(control, block1);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void block_trim_used(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    ulong size)
  {
    NetickAllocator.Assert(block->IsFree() == 0, "Netick Allocator: block must be used");
    if (!this.block_can_split(block, size))
      return;
    NetickAllocator.block_header_t* block1 = this.block_split(block, size);
    block1->SetPrevUsed();
    NetickAllocator.block_header_t* block2 = this.block_merge_next(control, block1);
    this.InsertBlock(control, block2);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_trim_free_leading(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    ulong size)
  {
    NetickAllocator.block_header_t* blockHeaderTPtr = block;
    if (this.block_can_split(block, size))
    {
      blockHeaderTPtr = this.block_split(block, size - NetickAllocator.block_header_overhead);
      blockHeaderTPtr->SetPrevFree();
      block->block_link_next(block);
      this.InsertBlock(control, block);
    }
    return blockHeaderTPtr;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe NetickAllocator.block_header_t* block_locate_free(
    NetickAllocator.control_t control,
    ulong size)
  {
    int fl = 0;
    int sl = 0;
    NetickAllocator.block_header_t* block = (NetickAllocator.block_header_t*) null;
    if (size != 0UL)
    {
      this.mapping_search(size, &fl, &sl);
      if (fl < 25)
        block = this.search_suitable_block(control, &fl, &sl);
    }
    if ((IntPtr) block != IntPtr.Zero)
    {
      NetickAllocator.Assert(block->GetSize() >= size);
      this.remove_free_block(control, block, fl, sl);
    }
    return block;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private unsafe void* block_prepare_used(
    NetickAllocator.control_t control,
    NetickAllocator.block_header_t* block,
    ulong size)
  {
    void* voidPtr = (void*) null;
    if ((IntPtr) block != IntPtr.Zero)
    {
      NetickAllocator.Assert(size > 0UL, "Netick Allocator: size must be non-zero");
      this.block_trim_free(control, block, size);
      block->block_mark_as_used(block);
      voidPtr = NetickAllocator.block_to_ptr(block);
    }
    return voidPtr;
  }

  private unsafe void control_construct(NetickAllocator.control_t control)
  {
    control.block_null->next_free = control.block_null;
    control.block_null->prev_free = control.block_null;
    control.fl_bitmap = 0U;
    for (int x = 0; x < 25; ++x)
    {
      control.sl_bitmap[x] = 0U;
      for (int y = 0; y < 32 /*0x20*/; ++y)
        control.SetBlock(x, y, control.block_null);
    }
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong tlsf_pool_overhead() => 2UL * NetickAllocator.block_header_overhead;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  private ulong tlsf_alloc_overhead() => NetickAllocator.block_header_overhead;

  internal unsafe void* AddPool(void* mem, ulong bytes)
  {
    ulong num = this.tlsf_pool_overhead();
    ulong size1 = this.align_down(bytes - num, 8UL);
    if ((int) mem % 8 != 0)
    {
      NetickLogger.Log((object) $"Netick Allocator: memory must be aligned by {(ValueType) 8U} bytes.\n");
      return (void*) null;
    }
    if (size1 < this.block_size_min || size1 > this.block_size_max)
    {
      NetickLogger.Log((object) $"Netick Allocator: memory size must be between {((uint) (num + this.block_size_min)).ToString()} and {(ValueType) (uint) ((num + this.block_size_max) / 256UL /*0x0100*/)} bytes.\n");
      return (void*) null;
    }
    int size2 = -(int) NetickAllocator.block_header_overhead;
    NetickAllocator.block_header_t* block = NetickAllocator.offset_to_block(mem, (ulong) size2);
    block->SetSize(size1);
    block->SetFree();
    block->SetPrevUsed();
    this.InsertBlock(this._control, block);
    NetickAllocator.block_header_t* blockHeaderTPtr = block->block_link_next(block);
    blockHeaderTPtr->SetSize(0UL);
    blockHeaderTPtr->SetUsed();
    blockHeaderTPtr->SetPrevFree();
    return mem;
  }

  public unsafe void* Malloc(ulong size, out int poolIndex, out long offset)
  {
    ulong size1 = this.adjust_request_size(size, 8UL);
    void* ptr1 = this.block_prepare_used(this._control, this.block_locate_free(this._control, size1), size1);
    if ((IntPtr) ptr1 != IntPtr.Zero)
    {
      poolIndex = this.GetPool(ptr1);
      void* ptr2 = this.Blocks[poolIndex].Ptr;
      offset = (sbyte*) ptr1 - (sbyte*) ptr2;
    }
    else
    {
      poolIndex = -1;
      offset = -1L;
    }
    return ptr1;
  }

  internal unsafe int GetPool(void* ptr)
  {
    for (int index = 0; index < this.Blocks.Count; ++index)
    {
      if (ptr >= this.Blocks[index].Ptr && (long) ptr < (long) this.Blocks[index].Ptr + this._poolSize)
        return index;
    }
    NetickLogger.LogError((object) "Netick: invalid Ptr");
    return -1;
  }

  public unsafe void* SafeMalloc(ulong size, out int poolIndex, out long offset, bool clearMem)
  {
    void* ptr = this.Malloc(size, out poolIndex, out offset);
    if ((IntPtr) ptr == IntPtr.Zero)
    {
      this.AddNewPool(true);
      ptr = this.Malloc(size, out poolIndex, out offset);
    }
    else if ((IntPtr) ptr == IntPtr.Zero)
      NetickLogger.LogError((object) $"Netick Allocator: allocation failed: allocator was unable to find a block of {size} bytes or bigger.\nPlease increase the memory allocator block size.");
    if ((IntPtr) ptr == IntPtr.Zero)
      NetickLogger.LogError((object) $"Netick Allocator: allocation failed: allocator was unable to find a block of {size} bytes or bigger.\nPlease increase the memory allocator block size.");
    if (clearMem)
      MemoryAllocation.Clear(ptr, (long) size);
    return ptr;
  }

  public unsafe void Free(void* ptr)
  {
    if ((IntPtr) ptr == IntPtr.Zero)
      return;
    NetickAllocator.block_header_t* block = this.block_from_ptr(ptr);
    NetickAllocator.Assert(block->IsFree() == 0, "Netick Allocator: block already marked as free");
    block->block_mark_as_free(block);
    this.InsertBlock(this._control, this.block_merge_next(this._control, this.block_merge_prev(this._control, block)));
  }

  internal struct block_header_t
  {
    public unsafe NetickAllocator.block_header_t* prev_phys_block;
    public IntPtr _size;
    public unsafe NetickAllocator.block_header_t* next_free;
    public unsafe NetickAllocator.block_header_t* prev_free;

    public ulong size
    {
      get => (ulong) (long) this._size;
      set => this._size = (IntPtr) (long) value;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public ulong GetSize() => this.size & 18446744073709551612UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void SetSize(ulong size)
    {
      ulong num = size;
      this.size = size | num & 3UL;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool IsLast() => this.GetSize() == 0UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int IsFree() => (int) ((long) this.size & 1L);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void SetFree() => this.size |= 1UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void SetUsed() => this.size &= 18446744073709551614UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int IsPrevFree() => (int) ((long) this.size & 2L);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void SetPrevFree() => this.size |= 2UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void SetPrevUsed() => this.size &= 18446744073709551613UL;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe NetickAllocator.block_header_t* block_prev(NetickAllocator.block_header_t* block)
    {
      NetickAllocator.Assert(block->IsPrevFree() != 0, "Netick Allocator: previous block must be free");
      return block->prev_phys_block;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe NetickAllocator.block_header_t* block_next(NetickAllocator.block_header_t* block)
    {
      NetickAllocator.block_header_t* block1 = NetickAllocator.offset_to_block(NetickAllocator.block_to_ptr(block), this.GetSize() - NetickAllocator.block_header_overhead);
      NetickAllocator.Assert(!this.IsLast());
      return block1;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe NetickAllocator.block_header_t* block_link_next(
      NetickAllocator.block_header_t* block)
    {
      NetickAllocator.block_header_t* blockHeaderTPtr1 = this.block_next(block);
      NetickAllocator.block_header_t* blockHeaderTPtr2 = block;
      blockHeaderTPtr1->prev_phys_block = blockHeaderTPtr2;
      return blockHeaderTPtr1;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe void block_mark_as_free(NetickAllocator.block_header_t* block)
    {
      this.block_link_next(block)->SetPrevFree();
      block->SetFree();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe void block_mark_as_used(NetickAllocator.block_header_t* block)
    {
      this.block_next(block)->SetPrevUsed();
      block->SetUsed();
    }
  }

  internal class control_t
  {
    public unsafe NetickAllocator.block_header_t* block_null;
    public uint fl_bitmap;
    public uint[] sl_bitmap = new uint[25];
    private unsafe NetickAllocator.block_header_t** _blocks;
    private unsafe byte* mem;

    public unsafe NetickAllocator.block_header_t* GetBlock(int x, int y)
    {
      return this._blocks[x * 32 /*0x20*/ + y];
    }

    public unsafe void SetBlock(int x, int y, NetickAllocator.block_header_t* block)
    {
      this._blocks[x * 32 /*0x20*/ + y] = block;
    }

    public unsafe control_t()
    {
      int num = 800;
      this.mem = (byte*) MemoryAllocation.Malloc((long) (sizeof (NetickAllocator.block_header_t) + sizeof (NetickAllocator.block_header_t*) * num));
      MemoryAllocation.Clear((void*) this.mem, (long) (sizeof (NetickAllocator.block_header_t) + sizeof (NetickAllocator.block_header_t*) * num));
      this._blocks = (NetickAllocator.block_header_t**) (this.mem + sizeof (NetickAllocator.block_header_t));
      this.block_null = (NetickAllocator.block_header_t*) this.mem;
    }

    unsafe ~control_t() => MemoryAllocation.Free((void*) this.mem);
  }

  public struct MemoryPool
  {
    public unsafe void* Ptr;
    public long ByteSize;
  }
}
